`timescale 1ns / 1ps
module spi_flash_master_tb();
reg 		clk;
reg 		rst_n;
reg 		flash_read;
reg 		flash_write;
reg 		flash_bulk_erase;
reg 		flash_sector_erase;
reg [23:0] 	flash_write_addr;
reg [ 7:0] 	flash_write_data_in;
reg [23:0]	flash_read_addr;
reg [ 9:0]	flash_write_size;	
reg [ 9:0] 	flash_read_size; 
reg [23:0]	flash_sector_addr;
reg  		flash_read_ID;

wire 		flash_read_ack;
wire 		flash_write_ack;
wire 		flash_bulk_erase_ack;
wire 		flash_sector_erase_ack;
wire 		flash_write_data_req;
wire [7:0] 	flash_read_data_out;
wire 		flash_read_data_valid;
wire		flash_read_ID_ack;
wire [7:0]	flash_ID_data_out;
wire 		flash_ID_valid;
wire        w_spi_cs    ;
wire        w_spi_clk   ;  
wire        w_spi_mosi  ; 
wire        w_spi_miso  ;
wire        WPn         ;
wire        HOLDn       ;
spi_flash_master spi_flash_master_m0(
	.sys_clk                     (clk                       ),
	.rst                         (~rst_n                    ),

	.spi_cs                      (w_spi_cs                  ),
	.spi_clk                     (w_spi_clk                 ),
	.spi_mosi                    (w_spi_mosi                ),
	.spi_miso                    (w_spi_miso                ),

    .flash_sector_erase          (flash_sector_erase        ),
	.flash_sector_addr           (flash_sector_addr        	),
	.flash_sector_erase_ack      (flash_sector_erase_ack    ),

	.flash_bulk_erase            (flash_bulk_erase          ),
	.flash_bulk_erase_ack        (flash_bulk_erase_ack      ),

	.flash_read_ID				 (flash_read_ID				),
	.flash_read_ID_ack			 (flash_read_ID_ack			),
	.flash_ID_data_out			 (flash_ID_data_out			),
	.flash_ID_valid				 (flash_ID_valid			),												

    .flash_write                 (flash_write               ),
	.flash_write_addr            (flash_write_addr         	),
	.flash_write_size            (flash_write_size          ),
	.flash_write_data_req        (flash_write_data_req      ),
	.flash_write_data_in         (flash_write_data_in    	),
	.flash_write_ack             (flash_write_ack           ),

	.flash_read                  (flash_read                ),
	.flash_read_addr             (flash_read_addr        	),
	.flash_read_size             (flash_read_size           ),
	.flash_read_data_out         (flash_read_data_out       ),
	.flash_read_data_valid       (flash_read_data_valid     ),
	.flash_read_ack              (flash_read_ack            )

);
pullup(w_spi_mosi   );
pullup(w_spi_miso   );
pullup(WPn          );
pullup(HOLDn        );
W25Q128JVxIM W25Q128JVxIM(
    .CSn                    (w_spi_cs       ), 
    .CLK                    (w_spi_clk      ), 
    .DIO                    (w_spi_mosi     ), 
    .DO                     (w_spi_miso     ), 
    .WPn                    (WPn            ), 
    .HOLDn                  (HOLDn          )
);

initial begin        
	clk = 0;    
	forever #10 clk= ~clk;   
end
initial begin
    rst_n = 0;
    flash_read = 0;
    flash_write = 0;
    flash_bulk_erase = 0;
    flash_sector_erase = 0;
	flash_write_addr = 24'd0;
	flash_write_data_in = 8'd0;
	flash_read_addr = 24'd0;
	flash_write_size = 9'd0;
	flash_read_size = 9'd0;
	flash_sector_addr = 24'd0;
	flash_read_ID = 0;

    #100;
    rst_n = 1;
    #100;


    // sector_erase(24'hab_cd_ef);
	// #2000;

	// bulk_erase;
	// #2000;

	flashwrite(24'd0,9'd5);
	#2000;

	flashread(24'd0,9'd5);
	#2000;

	flash_read_ID = 1;
	wait(flash_read_ID_ack == 1);
	#20;
	flash_read_ID = 0;
	#2000;
	
    $stop;
end
task bulk_erase;
	begin
		flash_bulk_erase = 1;
		wait(flash_bulk_erase_ack == 1);
		#20;
		flash_bulk_erase = 0;
	end
endtask
task sector_erase;
input [23:0] addr;
	begin
		flash_sector_erase = 1;    
		flash_sector_addr = addr;

		wait(flash_sector_erase_ack == 1);
		#20;
		flash_sector_erase = 0;
	end
endtask

task flashwrite;
	input [23:0] addr;
	input [8:0] write_data_count;
	begin
		flash_write = 1;
		flash_write_addr = addr;
		flash_write_size = write_data_count;
		flash_write_data_in = 8'ha5;

		repeat(write_data_count)
		begin
			wait(flash_write_data_req == 1);
			#40;
			flash_write_data_in = flash_write_data_in + 1'b1;
		end

		wait(flash_write_ack == 1);
		#20;
		flash_write = 0;
	end
endtask

task flashread;
	input [23:0] addr;
	input [8:0] read_data_count;
	begin
		flash_read = 1;
		flash_read_addr = addr;
		flash_read_size = read_data_count;
		wait(flash_read_ack == 1);
		#20;
		flash_read = 0;
	end
endtask


endmodule
